package com.gotloop.dao;

import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;

import com.gotloop.jdo.Loop;
import com.gotloop.util.DataConstants;

/**
 * Loop Data Access Object.
 * @author jibhaine
 *
 */
@Repository
@SuppressWarnings("unchecked")
public class LoopDAOImpl
extends AbstractDAOImpl<Loop, String>
implements LoopDAO {

	/**
	 * Logger for LoopDAOImpl.
	 */
	private static final Logger LOG = LoggerFactory.getLogger(LoopDAOImpl.class);

	/**
	 * Constraints to apply to select published and valid loops.
	 */
	private static final String[] PUBLISHED_LOOP = {"published == true"/*, "data != null"*/};
	
	@Override
	public Loop getLoopByTitle(String url) {
		return getById(url);
	}

	@Override
	public List<Loop> getLoopsByTag(String pTag, int startIndex, int itemsPerPage) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}

		PersistenceManager pm = getPersistenceManager();
		Query query = pm.newQuery(getEntityClass());

		query.setFilter("tags.contains(:pTag)");
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setFilter("creationDate != null");
		query.setOrdering("creationDate ascending");
		query.setRange(startIndex, startIndex + itemsPerPage);

		
		List<Loop> loopList = (List<Loop>) query.execute(pTag);

		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned {}", loopList);
		}
		return loopList;
	}

	@Override
	public List<Loop> getLoopsByAuthor(String pName, int startIndex, int itemsPerPage) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}

		PersistenceManager manager = getPersistenceManager();
		
		Query query = manager.newQuery(getEntityClass());
		query.setFilter("author.name = :pName");
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setFilter("creationDate != null");
		query.setOrdering("creationDate asc");
		query.setRange(startIndex, startIndex + itemsPerPage);
		
		List<Loop> loopList = (List<Loop>) query.execute(pName);
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned {}", loopList);
		}
		return loopList;
	}

	@Override
	public List<Loop> getLoopsByDay(Date pDay, int startIndex, int itemsPerPage) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}

		PersistenceManager pManager = getPersistenceManager();
		
		Query query = pManager.newQuery(getEntityClass());
		query.setFilter("creationDate == :pDay");
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setFilter("creationDate != null");
		query.setOrdering("creationDate ascending");
		query.setRange(startIndex, startIndex + itemsPerPage);
				
		List<Loop> loopList = (List<Loop>) query.execute(pDay);

		loopList = (List<Loop>) pManager.detachCopyAll(loopList);
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned {}", loopList);
		}
		return loopList;
	}

	@Override
	public List<Loop> getLoopsByMonth(Date monthDate, int startIndex, int itemsPerPage) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}

		PersistenceManager manager = getPersistenceManager();
		
		Query query = manager.newQuery(getEntityClass());
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setFilter("creationDate == :monthDate");
		query.setOrdering("creationDate ascending");

		query.setRange(startIndex, startIndex + itemsPerPage);
		
		List<Loop> loopList = (List<Loop>) query.execute(monthDate);
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned {}", loopList);
		}
		return loopList;
	}

	@Override
	public Long howManyLoopsThisYear(Date yearDate) {		
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}

		PersistenceManager manager = getPersistenceManager();
		
		StringBuffer queryString = new StringBuffer(DataConstants.STRING_MIN_CAPACITY);
		queryString.append("select count(*) from Loop l ");
		queryString.append("where YEAR(l.creationDate) = YEAR(:day) ");
		
		Query query = manager.newQuery(queryString.toString());
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setOrdering("l.creationDate ascending");

		query.declareParameters("java.util.date day");
		
		Long count = (Long) query.execute(yearDate);
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned ");
		}
		return count;
	}

	@Override
	public Long howManyLoopsThisMonth(Date monthDate) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}
		PersistenceManager manager = getPersistenceManager();
		
		
		StringBuffer queryString = new StringBuffer(DataConstants.STRING_MIN_CAPACITY);
		queryString.append("select count(*) from Loop l where MONTH(l.creationDate) = MONTH(:day) ");
		Query query = manager.newQuery(queryString.toString());
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setOrdering("l.creationDate ascending");
		query.declareParameters("java.util.date day");
		Long count = (Long) query.execute(monthDate);
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned ");
		}
		return count;
	}

	@Override
	public Long howManyLoopsThisDay(final Date dayDate) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}

		PersistenceManager pManager = getPersistenceManager();
		
		Query query = pManager.newQuery("select count(*) from Loop l " 
				+ "where DAY(l.creationDate) = DAY(:day) ");
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setOrdering("l.creationDate ascending");
		query.declareParameters("java.util.date day");
			
		Long count = (Long) query.execute(dayDate);
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned " + count);
		}
		return count;
	}

	@Override
	public Long howManyLoopsForThisTag(String tag) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Start");
		}

		PersistenceManager pManager = getPersistenceManager();
				
		Query query = pManager.newQuery("select count(*) from Loop l ");
		
		for (String s : PUBLISHED_LOOP) {
			query.setFilter(s);
		}
		query.setFilter("l.tags.contains(:tag)");
		query.setOrdering("l.creationDate ascending");
		query.declareParameters("String tag");
		
		Long count = (Long) query.execute(tag);
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("End, returned " + count);
		}
		return count;
	}



}
